/**
 * @fileoverview
 * This script defines a widget for interacting with expression data from flyatlas.
 * @author <a href="http://purl.org/net/aliman">Alistair Miles</a>
 * @version $Revision:538 $ on $Date: 2008-08-27 09:08:41 +0100 (Wed, 27 Aug 2008) $ by $Author: aliman $
 * @requires flyui.util
 * @requires flyui.sparql.Service
 * @requires flyui.flyatlas.Service
 * @requires YAHOO.util.Connect
 * @requires jQuery
 * For license terms see http://flyui.googlecode.com
 */
 
flyui.namespace("flyui.flyatlas");
 
 
 
 
 

/*
 * ----------------------------------------------------------------
 *                             WIDGET
 * ----------------------------------------------------------------
 */







flyui.flyatlas.BatchWidget = function( service, renderer ) {
    var _context = "flyui.flyatlas.BatchWidget";
    try {
        
        flyui.debug("call private constructor", _context);
        this.__init__(service, renderer);
        
    } catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
    
}



 
 



/** @private */
flyui.flyatlas.BatchWidget.prototype._controller = null;

/**
 * @private
 * @type flyui.mvcutils.GenericModel2
 */ 
flyui.flyatlas.BatchWidget.prototype._model = null;

/**
 * @private
 */
flyui.flyatlas.BatchWidget.prototype._renderer = null;

/**
 * @private
 */
flyui.flyatlas.BatchWidget.prototype._service = null;










/**
 * @private
 */
flyui.flyatlas.BatchWidget.prototype.__init__ = function( service, renderer ) {
    var _context = "flyui.flyatlas.BatchWidget.prototype.__init__";
    try {
        
        this._service = service;
        this._renderer = renderer;
        
        flyui.debug("create a model", _context);
        this._model = new flyui.mvcutils.GenericModel2();
        this._model.setDefinition(flyui.flyatlas.BatchWidget.modelDefinition);
        
        flyui.debug("create a controller", _context);
        this._controller = new flyui.flyatlas.BatchWidget.Controller(this._model, service, this);
        
        flyui.debug("connect the renderer to the model", _context);
        this._renderer.connect(this._model);
        
    } catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
};







/**
 * @public
 * @param {Array<String>} querynames
 * @param {Array<String>} flybaseids
 */
flyui.flyatlas.BatchWidget.prototype.getAssaysByGeneBatch = function( querynames, flybaseids ) {
    var _context = "flyui.flyatlas.BatchWidget.prototype.getAssaysByGeneBatch";
    try {
        
        flyui.debug("pass ["+querynames+"], ["+flybaseids+"] through to controller", _context);
        this._controller.getAssaysByGeneBatch(querynames, flybaseids);
        
    } catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
};







/*
 * ----------------------------------------------------------------
 *                             CONTROLLER
 * ----------------------------------------------------------------
 */






/**
 * @class
 */
flyui.flyatlas.BatchWidget.Controller = function( model, service, controllee ) {
    var _context = "flyui.flyatlas.BatchWidget.Controller";
    try {
        
        this._model = null;
        this._service = null;
        this._controllee = null;
        
        flyui.debug("call private constructor", _context);
        this.__init__(model, service, controllee);        
        
    } catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
};








/**
 * @private
 */
flyui.flyatlas.BatchWidget.Controller.prototype.__init__ = function( model, service, controllee ) {
    var _context = "flyui.flyatlas.BatchWidget.Controller.prototype.__init__";
    try {
        
        this._model = model;
        this._service = service;
        this._controllee = controllee;
        
    } catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
};








/**
 * @public
 */
flyui.flyatlas.BatchWidget.Controller.prototype.getAssaysByGeneBatch = function( querynames, flybaseids ) {
    var _context = "flyui.flyatlas.BatchWidget.Controller.prototype.findGenesByAnyNameBatch";
    try {
        
        flyui.info("getAssaysByGeneBatch: "+querynames+" || "+flybaseids, _context);
        flyui.debug("pass through to private implementation", _context);
        this._getAssaysByGeneBatch(querynames, flybaseids, this._getAssaysByGeneBatchSuccess(), this._getAssaysByGeneBatchFailure());
        
    } catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
};








/**
 * @private
 */
flyui.flyatlas.BatchWidget.Controller.prototype._getAssaysByGeneBatch = function( querynames, flybaseids, success, failure ) {
    var _context = "flyui.flyatlas.BatchWidget.Controller.prototype._getAssaysByGeneBatch";
    try {
        
        flyui.debug("querynames: "+querynames, _context);
        flyui.debug("flybaseids: "+flybaseids, _context);
        
        flyui.debug("set state pending", _context);
        this._model.set("STATE", "PENDING");
        
        flyui.debug("set model property query", _context);
        this._model.set("QUERY", [querynames, flybaseids]);

        flyui.debug("set result null", _context);
        this._model.set("RESULTS", null);
                
        flyui.debug("set message null", _context);
        this._model.set("MESSAGE", null);
                
        flyui.debug("kick off request", _context);
        this._service.getAssaysByFlybaseGeneIdBatch(flybaseids, success, failure);        
        
    } catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
};









/**
 * @private
 */
flyui.flyatlas.BatchWidget.Controller.prototype._getAssaysByGeneBatchSuccess = function() {
    var _context = "flyui.flyatlas.BatchWidget.Controller.prototype._getAssaysByGeneBatchSuccess";
    var self = this;
    /**
     * @param {Object<String,<Array<AssayGroup>>} results a map from flybaseids to arrays of AssayGroup objects
     */
    return function( results ) {
        try {
            
            flyui.info("request success", _context);
            
            flyui.debug("set model results", _context);
            self._model.set("RESULTS", results);
            
            flyui.debug("set model state", _context);
            self._model.set("STATE", "READY");
            
            var explanation = "Values shown are mean mRNA signal plus or minus standard error on the mean; cell background colour indicates results of T-test comparison with whole fly, green is up, red is down, white is no change. See also Chintapalli, V. R., Wang, J. and Dow, J. A. T. (2007). Using FlyAtlas to identify better Drosophila models of human disease. <a href='http://www.nature.com/ng/journal/v39/n6/abs/ng2049.html'>Nature Genetics 39: 715-720</a>.";
            self._model.set("MESSAGE", explanation);
            
        } catch (unexpected) {
            flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
            throw unexpected;    
        }
    };
};







/**
 * @private
 */
flyui.flyatlas.BatchWidget.Controller.prototype._getAssaysByGeneBatchFailure = function() {
    var _context = "flyui.flyatlas.BatchWidget.Controller.prototype._getAssaysByGeneBatchFailure";
    var self = this;
    /**
     * @param {ResponseObject} response
     */
    return function( response ) {
        try {
            
            flyui.err("request failed: "+response.status+" "+response.statusText, _context);
            self._model.set("MESSAGE", "there was an error retrieving data from the server, see the logs for more info");
            self._model.set("STATE", "SERVERERROR");
            
        } catch (unexpected) {
            flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
            throw unexpected;    
        }
    };
};







/*
 * ----------------------------------------------------------------
 *                             MODEL DEFINITION
 * ----------------------------------------------------------------
 */





/** 
 * @type Object
 */
flyui.flyatlas.BatchWidget.modelDefinition = {

    properties : [ "STATE", "RESULTS", "MESSAGE", "QUERY" ],
    
    values : {
        "STATE" : [ "READY", "PENDING", "SERVERERROR", "UNEXPECTEDERROR" ]
    },
    
    initialize : function( data ) {
        data["STATE"] = "READY";
        data["RESULTS"] = null;
        data["MESSAGE"] = null;
        data["QUERY"] = null;
    }

};







/*
 * ----------------------------------------------------------------
 *                             DEFAULT RENDERER
 * ----------------------------------------------------------------
 */







flyui.flyatlas.BatchWidget.DefaultRenderer = function() {};


/** 
 * @private 
 * @type Element
 */
flyui.flyatlas.BatchWidget.DefaultRenderer.prototype._canvas = null;

/**
 * @private 
 * @type Element
 */
flyui.flyatlas.BatchWidget.DefaultRenderer.prototype._pendingPane = null;

/**
 * @private 
 * @type Element
 */
flyui.flyatlas.BatchWidget.DefaultRenderer.prototype._resultsSummaryPane = null;

/**
 * @private 
 * @type Element
 */
flyui.flyatlas.BatchWidget.DefaultRenderer.prototype._resultsPane = null;

/**
 * @private 
 * @type Element
 */
flyui.flyatlas.BatchWidget.DefaultRenderer.prototype._messagePane = null;





/**
 * Set the DOM element to which this renderer applies and initialise it.
 * @param {Element} canvas
 */
flyui.flyatlas.BatchWidget.DefaultRenderer.prototype.setCanvas = function( canvas ) {
    var _context = "flyui.flyatlas.BatchWidget.DefaultRenderer.prototype.setCanvas";
    try {
        
        flyui.debug("set canvas", _context);
        this._canvas = $(canvas);
        this._initCanvas();
        
        
    } catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
};






/**
 * @private
 * @param {Element} canvas
 */
flyui.flyatlas.BatchWidget.DefaultRenderer.prototype._initCanvas = function() {
    var _context = "flyui.flyatlas.BatchWidget.DefaultRenderer.prototype._initCanvas";
    try {
        
        flyui.debug("begin init canvas", _context);
        
        var canvas = this._canvas;
        canvas.addClass("batchFlyatlasWidget");

        var pp = $("<p class='pendingPane'>pending (please wait, this can take up to 10 seconds) ...</p>").hide();
        canvas.append(pp);
        this._pendingPane = pp;

        var rsp = $("<p class='resultsSummaryPane'>this text should never be displayed</p>").hide();
        canvas.append(rsp);
        this._resultsSummaryPane = rsp;
        
        var rp = $("<div class='resultsPane'></div>").hide();
        canvas.append(rp);
        this._resultsPane = rp;
        
        var mp = $("<p class='messagePane'>this text should never be displayed</p>").hide();
        canvas.append(mp);
        this._messagePane = mp;            

        flyui.debug("init canvas done", _context);
        
    } catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
};





/**
 * @public
 */
flyui.flyatlas.BatchWidget.DefaultRenderer.prototype.connect = function( model ) {
    var _context = "flyui.flyatlas.BatchWidget.DefaultRenderer.prototype.connect";
    try {
        
        flyui.debug("connect to model", _context);
        model.subscribeAll(this._onModelChanged, this);
        
    } catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
};





/**
 * @private
 */
flyui.flyatlas.BatchWidget.DefaultRenderer.prototype._onModelChanged = function( type, args, self ) {
    var _context = "flyui.flyatlas.BatchWidget.DefaultRenderer.prototype._onModelChanged";
    try {
        
        var handlers = {
            "STATE":"_onStateChanged",
            "QUERY":"_onQueryChanged",
            "RESULTS":"_onResultsChanged",
            "MESSAGE":"_onMessageChanged"
        };
        var handler = handlers[type];
        flyui.debug("call model changed handler: "+handler, _context);
        self[handler](args[0], args[1], args[2]);
        
    } catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
};






/**
 * @private
 */
flyui.flyatlas.BatchWidget.DefaultRenderer.prototype._onQueryChanged = function( from, to, get ) {
    var _context = "flyui.flyatlas.BatchWidget.DefaultRenderer.prototype._onQueryChanged";
    try {
        
        // do nothing, we will access the value later
        flyui.debug("query changed from "+from+" to "+to, _context);
        
    } catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
};






/**
 * @private
 */
flyui.flyatlas.BatchWidget.DefaultRenderer.prototype._onStateChanged = function( from, to, get ) {
    var _context = "flyui.flyatlas.BatchWidget.DefaultRenderer.prototype._onStateChanged";
    try {
        
        flyui.debug("state changed from "+from+" to "+to, _context);

        if ( to == "PENDING" ) {
            this._pendingPane.show();
            this._messagePane.hide();
            this._resultsSummaryPane.hide();
            this._resultsPane.hide();
        }
        else if ( to == "READY" ) {
            this._pendingPane.hide();
            this._messagePane.show();
            this._resultsSummaryPane.show();
            this._resultsPane.show();         
        } 
        else if ( to == "SERVERERROR" || to == "UNEXPECTEDERROR" ) {
            this._pendingPane.hide();
            this._messagePane.show();
            this._resultsSummaryPane.hide();
            this._resultsPane.hide();         
        } 
        else {
            // this should never happen
            throw {message:"invalid state: "+to};
        }
        
    } catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
};






/**
 * @private
 */
flyui.flyatlas.BatchWidget.DefaultRenderer.prototype._onResultsChanged = function( from, to, get ) {
    var _context = "flyui.flyatlas.BatchWidget.DefaultRenderer.prototype._onResultsChanged";
    try {
        
        flyui.debug("results changed to: "+to, _context);
        
        if (to == null) {
            flyui.debug("empty results summary pane", _context);
            this._resultsSummaryPane.empty();
            flyui.debug("empty results pane", _context);
            this._resultsPane.empty();
        } 
        
        else {

            var query = get("QUERY");
            
            flyui.debug("render results summary", _context);
            this._renderResultsSummary(query, to);
    
            flyui.debug("render results", _context);
            this._renderResults(query, to);        
            
        }
        
    } catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
};







/**
 * @private
 */
flyui.flyatlas.BatchWidget.DefaultRenderer.prototype._onMessageChanged = function( from, to, get ) {
    var _context = "flyui.flyatlas.BatchWidget.DefaultRenderer.prototype._onMessageChanged";
    try {
        
        flyui.debug("message changed to: "+to, _context);
        
        if (to == null) {
            flyui.debug("empty messsage pane", _context);
            this._messagePane.empty();
        } 
        
        else {

            this._messagePane.html(to);
            
        }
        
    } catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
};









/**
 * @private
 * @param {Object<String,<Array<AssayGroup>>} results a map from flybaseids to arrays of assay group objects
 */
flyui.flyatlas.BatchWidget.DefaultRenderer.prototype._renderResultsSummary = function( query, results ) {
    var _context = "flyui.flyatlas.BatchWidget.DefaultRenderer.prototype._renderResultsSummary";
    try {
        
        flyui.debug("render results summary", _context);

        var querynames = query[0];
        var flybaseids = query[1];
        
        var content = "";
        var count = 0;        
        for (var i=0;i<querynames.length;i++) {
//            content += "probes for "+querynames[i] + " ("+flybaseids[i]+"): ";
            var groups = results[flybaseids[i]];
            count += groups.length;
//            if (groups.length == 0) {
//                content += "no matching probes; ";
//            }
//            else {
//                for (var j=0;j<groups.length;j++) {
//                    content += "<a href='http://flyatlas.org/probeset.cgi?name="+groups[j].affy_id+"'>"+groups[j].affy_id+"</a>" + " ";
//                }
//            }
//            content += "<br/>";
        }
        
        var content = "found ";
        content += count;
        content += " matching probe";
        content += (count == 0 || count > 1) ? "s " : " ";
        content += "from <a href='http://www.flyatlas.org'>flyatlas.org</a> (data obtained on 2008-09-16) ...";

        this._resultsSummaryPane.html(content);
        
    } catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
};








/**
 * @private
 * @param {Object<String,<Array<Gene>>} results a map from names in the query to arrays of gene objects
 */
flyui.flyatlas.BatchWidget.DefaultRenderer.prototype._renderResults = function( query, results ) {
    var _context = "flyui.flyatlas.BatchWidget.DefaultRenderer.prototype._renderResults";
    try {
        flyui.debug("render results", _context);

        var querynames = query[0];
        var flybaseids = query[1];
        
        var content = "<table><thead><tr><th>gene</th><th>probe</th>";
        for (var i=0;i<flyui.flyatlas.tissues.length;i++) {
            var tissue = flyui.flyatlas.tissues[i];
            content += "<th>" + tissue + "</th>";
        }
        content += "</tr></thead>"
        
        for (var i=0;i<querynames.length;i++) {
            var n = querynames[i];
            var id = flybaseids[i];
            var groups = results[id];
            if (groups.length > 0) {
                content += "<tbody>";
                for (var j=0; j<groups.length;j++) {
                    content += "<tr>";
//                    if (j == 0 && groups.length > 1) {
//                        content += "<td rowspan='"+groups.length+"'>" + n + "</td>";
//                    }
//                    else if (j == 0) {
//                        content += "<td>" + n + "</td>";                        
//                    }
                    content += "<td>" + n + "</td>";                        
                    var group = groups[j];
                    content += "<td>" + "<a href='http://flyatlas.org/probeset.cgi?name="+group.affy_id+"'>"+group.affy_id+"</a>" + "</td>";
                    for (var k=0;k<flyui.flyatlas.tissues.length;k++) {
                        var tissue = flyui.flyatlas.tissues[k];
                        var change = group[tissue].change;
                        var mean = group[tissue].mean;
                        var sem = group[tissue].sem;
                        var clsname = "flyatlasChangeNone";
                        if (change == "Up") {
                            clsname = "flyatlasChangeUp";
                        }
                        else if (change == "Down") {
                            clsname = "flyatlasChangeDown";
                        }
                        content += "<td class='"+clsname+"'>" + mean + "±" +sem + "</td>";
                    }
                    content += "</tr>";
                }
                
                content += "</tbody>";    
            }
        }
        
        
        content += "</table>";
        this._resultsPane.html(content);
        
    } catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }
};





















